// Keywords: range expansion, colonization, population spread, migration

initialize() {
	defineConstant("K", 1000);   // carrying capacity per subpop
	defineConstant("N", 10);     // number of subpopulations
	defineConstant("M", 0.01);   // migration probability
	defineConstant("R", 1.04);   // mean reproduction (as first parent)
	
	initializeSLiMModelType("nonWF");
	initializeMutationType("m1", 0.5, "f", 0.0);
	m1.convertToSubstitution = T;
	initializeGenomicElementType("g1", m1, 1.0);
	initializeGenomicElement(g1, 0, 99999);
	initializeMutationRate(1e-7);
	initializeRecombinationRate(1e-8);
}
reproduction() {
	// individuals reproduce locally, without dispersal
	litterSize = rpois(1, R);
	
	for (i in seqLen(litterSize))
	{
		// generate each offspring with an independently drawn mate
		mate = subpop.sampleIndividuals(1, exclude=individual);
		if (mate.size())
			subpop.addCrossed(individual, mate);
	}
}
1 early() {
	// create an initial population of 100 individuals, the rest empty
	for (i in seqLen(N))
		sim.addSubpop(i, (i == 0) ? 100 else 0);
}
1 late() {
	// set up a log file
	log = community.createLogFile("sim_log.txt", sep="\t", logInterval=10);
	log.addCycle();
	log.addPopulationSize();
	log.addMeanSDColumns("size", "sim.subpopulations.individualCount;");
	log.addCustomColumn("pop_migrants", "sum(sim.subpopulations.individuals.migrant);");
	log.addMeanSDColumns("migrants",
		"sapply(sim.subpopulations, 'sum(applyValue.individuals.migrant);');");
}
early() {
	// non-overlapping generations; kill off the parental generation
	inds = sim.subpopulations.individuals;
	sim.killIndividuals(inds[inds.age > 0]);
	
	// pre-migration density-dependent fitness for each subpop
	for (subpop in sim.subpopulations)
		subpop.fitnessScaling = K / subpop.individualCount;
}
survival() {
	// honor SLiM's survival decision
	if (!surviving)
		return NULL;
	
	// migrate with probability M
	if (runif(1) >= M)
		return NULL;
	
	// migrate the focal individual to an adjacent subpop
	subpops = sim.subpopulations;
	newSubpopID = subpop.id + (-1 + rbinom(1, 1, 0.5) * 2);	// -1 or +1
	newSubpop = subpops[subpops.id == newSubpopID];
	if (newSubpop.size())
		return newSubpop;
	return NULL;
}
1001 late() { sim.outputFixedMutations(); }
